package com.xiao.user.controller;


import com.xiao.user.service.CurdService;
import com.xiao.user.service.criteria.Criteria;
import com.xiao.user.web.util.HeaderUtil;
import com.xiao.user.web.util.PaginationUtil;
import com.xiao.user.web.util.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Optional;

/**
 * @author zhoushaofeng
 */
@Slf4j
public abstract class AbstractResource<E, D, K> {
    private final String entityName;
    private final CurdService<E, D, K> service;

    @Value("${spring.application.name}")
    protected String applicationName;

    public AbstractResource(CurdService<E, D, K> service, String entityName) {
        this.service = service;
        this.entityName = entityName;
    }

    protected abstract K getId(D dto);

    public ResponseEntity<D> createEntity(D dto)
            throws URISyntaxException {

        log.debug("REST request to save object: {}", dto);

//        if (getId(dto) != null) {
//            throw new BadRequestAlertException("A object already have an ID", entityName, "idexists");
//        }

        D result = service.create(dto);
//        Optional<D> optionalDto = service.findById(getId(result));
        HttpHeaders headers = HeaderUtil.createEntityCreationAlert(applicationName, false, entityName, getId(result).toString());
        return ResponseEntity.created(new URI(entityName + "/" + getId(result)))
                .headers(headers)
                .body(result);
    }

    public ResponseEntity<D> updateEntity(K id, D dto) {
//        if (getId(dto) == null) {
//            throw new BadRequestAlertException("Invalid id", entityName, "idnull");
//        }

        D result = service.update(id, dto);
        Optional<D> optionalDto = service.findById(getId(result));
        return ResponseEntity.ok()
                .headers(HeaderUtil.createEntityUpdateAlert(applicationName, false, entityName, getId(result).toString()))
                .body(result);
    }

    public ResponseEntity<D> findEntityById(@PathVariable K id) {
        Optional<D> entity = service.findById(id);
        return ResponseUtil.wrapOrNotFound(entity);
    }

    public <C> ResponseEntity<List<D>> findAllByPage(Criteria criteria, Pageable pageable) throws InterruptedException {
        if (log.isDebugEnabled()) {
            log.debug("REST request to get entity by criteria: {}", criteria);
        }

        Page<D> page = service.findByCriteria(criteria, pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(
                ServletUriComponentsBuilder.fromCurrentRequest(),
                page);
        List<D> items = page.getContent();
        return ResponseEntity.ok().headers(headers).body(items);
    }

    public ResponseEntity<Void> deleteEntity(K id) {

        service.delete(id);
        HttpHeaders headers = HeaderUtil.createEntityDeletionAlert(
                applicationName,
                false,
                entityName,
                id.toString());

        return ResponseEntity
                .noContent()
                .headers(headers)
                .build();
    }

    public ResponseEntity<Void> deleteEntities(K[] ids) {

        service.deleteBatch(ids);
        HttpHeaders headers = HeaderUtil.createEntityDeletionAlert(
                applicationName,
                false,
                entityName,
                ids.toString());

        return ResponseEntity
                .noContent()
                .headers(headers)
                .build();
    }
}
